package main

/**
与用户交互
@author 学者科技
@date 2022/5/17
*/

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"

	"cloudea.com/container/bridge"
	"cloudea.com/container/config"
	"cloudea.com/container/domain"
	"cloudea.com/container/utils"
)

/** 打印命令格式 */
func cmd() {
	fmt.Println("命令格式:  container <command> args...")
	fmt.Println("例如:")
	fmt.Println("container pull <name>:<tag>")
	fmt.Println("container images")
	fmt.Println("container rmi <name>:<tag> ")
	fmt.Println("container run options <name>:<tag> [<cmd>...]")
	fmt.Println("container ps [-a]")
	fmt.Println("container rm  <container>")
	fmt.Println("container exec -d|-it <container> <cmd>")
	fmt.Println("container help")
	fmt.Println("run 命令的选项：  [-d|-it] [--cpu=<cpu-quota>] [--mem=<mem-size>] ")
	fmt.Println("--name=<name>     必选，容器的名字")
	fmt.Println("--it              可选，容器前台运行")
	fmt.Println("--cpu=<cpu-quota> cpu个数，可以为小数或整数 ")
	fmt.Println("--mem=<mem-size>  内存大小，例如1G,1M")
}

/** 打印命令格式并退出  */
func badFormat() {
	fmt.Println("bad format!")
	cmd()
	os.Exit(-1)
}

/** 解析镜像接取命令 */
func parsePull() {
	if len(os.Args) <= 2 {
		badFormat()
	}
	name, tag := utils.ParseNameTag(os.Args[2])
	domain.APPLICATION.Pull(name, tag)
}

/** 解析镜像列表命令 */
func parseImages() {
	domain.APPLICATION.Images()
}

/** 解析镜像删除命令 */
func parseRmi() {
	if len(os.Args) <= 2 {
		badFormat()
	}
	domain.APPLICATION.Rmi(utils.ParseNameTag(os.Args[2]))
}

/** 解析容器运行命令 */
func parseRun() {
	if len(os.Args) < 3 {
		badFormat()
	}

	pos := 2
	var options []string
	for pos < len(os.Args) {
		if str, found := strings.CutPrefix(os.Args[pos], "--"); found {
			options = append(options, str)
			pos++
			continue
		}
		break
	}
	if pos >= len(os.Args) {
		badFormat()
	}

	// 处理选项
	containerName := ""
	isDaemon := true
	cpuQuota := "max" //默认不会限制CPU
	memQuota := "max" //默认不会限制内存
	for _, option := range options {
		optionTuple := strings.SplitN(option, "=", 2)
		if optionTuple[0] == "name" {
			if len(optionTuple) == 1 {
				badFormat()
			}
			containerName = optionTuple[1]
		} else if optionTuple[0] == "it" {
			isDaemon = false
		} else if optionTuple[0] == "cpu" {
			if len(optionTuple) == 1 {
				badFormat()
			}
			cpuNum, err := strconv.ParseFloat(optionTuple[1], 64)
			if err != nil {
				badFormat()
			}
			cpuQuota = fmt.Sprint(int64(cpuNum * float64(config.CPU_PERIOD)))
		} else if optionTuple[0] == "mem" {
			if len(optionTuple) == 1 {
				badFormat()
			}
			memQuota = optionTuple[1]
		}
	}

	if containerName == "" {
		fmt.Println("需要指定容器名!")
		badFormat()
	}

	name, tag := utils.ParseNameTag(os.Args[pos])
	cmd := os.Args[pos+1:]
	domain.APPLICATION.Run(name, tag, containerName, isDaemon, cpuQuota, memQuota, cmd)
}

/** 解析容器查看命令 */
func parsePs() {
	showAll := len(os.Args) >= 3 && os.Args[2] == "-a"
	domain.APPLICATION.Ps(showAll)
}

/** 解析容器删除命令 */
func parseRm() {
	if len(os.Args) <= 2 {
		badFormat()
	}
	containerName := os.Args[2]
	domain.APPLICATION.Rm(containerName)
}

/** 解析容器执行命令 */
func parseExec() {
	//  只有当容器主进程在跑的时候，EXEC才有效。
	if len(os.Args) < 5 {
		badFormat()
	}

	runFlag := os.Args[2]
	isDaemon := true
	if runFlag == "-d" {
		isDaemon = true
	} else if runFlag == "-it" {
		isDaemon = false
	} else {
		badFormat()
	}
	containerName := os.Args[3]
	cmd := os.Args[4:]
	domain.APPLICATION.Exec(containerName, isDaemon, cmd)
}

func parseSub() {
	// 处理子进程
	if len(os.Args) <= 2 {
		fmt.Println("错误的子进程调用")
	}

	containerName := os.Args[2]
	domain.APPLICATION.Run2(containerName)
}

func main() {
	if os.Geteuid() != 0 {
		log.Fatal("需要root权限运行此程序")
	}

	// 建立网桥
	utils.Assert(bridge.EnsureContainer0())

	// 初始化
	if !config.CONFIG.Inited {
		utils.Assert(bridge.EnsureInternet())
		config.CONFIG.Inited = true
		config.CONFIG.Save()
	}

	// 如果没有参数，打印格式并退出
	if len(os.Args) <= 1 {
		cmd()
		os.Exit(0)
	}
	// 根据第一个参数决定要执行什么命令
	command := os.Args[1]
	switch command {
	case "pull":
		parsePull()
	case "images":
		parseImages()
	case "rmi":
		parseRmi()
	case "run":
		parseRun()
	case "ps":
		parsePs()
	case "rm":
		parseRm()
	case "exec":
		parseExec()
	case "help":
		cmd()
	case "sub":
		parseSub()
	default:
		badFormat()
	}
}
